# -*- coding: utf-8 -*-
import re
import string
from bs4 import BeautifulSoup
from requests import get as get_url
from custom_exceptions import EmptyResultsTable
import random


def singleton(cls):
    instances = {}

    def get_instance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return get_instance


def process_search_url(user_url, UserUrlAdvert, on_save_url=False):
    parser = Parser()
    r = get_url(user_url.url)
    soup = BeautifulSoup(r.content)
    print(soup)
    table = parser.get_result_table(soup)
    if not table:
        raise EmptyResultsTable('no results on drom.ru')
    user_url_adverts = UserUrlAdvert.objects.filter(user_url=user_url)
    new_adverts = parser.find_new_adverts(user_url_adverts, parser.get_adverts(table))
    for advert_id in new_adverts.keys():
        user_url_advert = UserUrlAdvert(user_url=user_url, advert_id=advert_id,
                                        advert_price=new_adverts[advert_id]['advert_price'], processed=on_save_url)
        user_url_advert.save()


@singleton
class Parser:

    def __init__(self):
        self.val = random.random()

    def get_result_table(self, soup):
        h4 = soup.find("h4", text="Объявления в архиве:")
        if not h4:
            return soup.find("table", "newCatList")
        item = h4.previousSibling
        while item == u"\n":
            item = item.previousSibling
        if hasattr(item, 'name') and item.name == 'div':
            return item.find("table", "newCatList")

    def get_advert_href(self, tr):
        advert_id_td = tr.find("td", "c_i")
        if not advert_id_td: return None
        advert_id_a = advert_id_td.find("a", href=re.compile('^http://*'))
        if not advert_id_a: return None
        advert_id_href = advert_id_a['href']
        if not advert_id_href: return None
        return advert_id_href

    def get_advert_id(self, advert_id_href):
        advert_id = advert_id_href.split('/')[-1].split('.')[0]
        return int(advert_id)

    def get_advert_price(self, tr):
        advert_price_td = tr.findAll("td")[-1]
        if not advert_price_td: return None
        advert_price_span = advert_price_td.find("span", "f14")
        if not advert_price_span: return None
        advert_price_text = string.join(advert_price_span.string.split()[:-1], "")
        advert_price = int(advert_price_text)
        return advert_price

    def get_adverts(self, table):
        adverts = {}
        table_tr = table.findAll("tr")[1:]
        result = {'link': []}
        for tr in table_tr:
            advert_href = self.get_advert_href(tr)
            if not advert_href: continue
            advert_id = self.get_advert_id(advert_href)
            if not advert_id: continue
            advert_price = self.get_advert_price(tr)
            if not advert_price: continue
            adverts[advert_id] = {'advert_price': advert_price, 'advert_href': advert_href}
        return adverts

    def find_new_adverts(self, exist_adverts, parsed_adverts):
        new_adverts = []
        for adv in exist_adverts:
            try:
                exist_advert_price = parsed_adverts[adv.advert_id]['advert_price']
                if exist_advert_price <= adv.advert_price:
                    del parsed_adverts[adv.advert_id]
            except KeyError:
                pass
        return parsed_adverts